package com.bsth.entity.realcontrol;

import com.bsth.entity.sys.SysUser;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import javax.persistence.*;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * 实际排班计划明细。
 */
@Entity
@Table(name = "bsth_c_s_sp_info_real")
@NamedEntityGraphs({
    @NamedEntityGraph(name = "scheduleRealInfo_cTasks", attributeNodes = {
            @NamedAttributeNode("cTasks")
    })
})
public class ScheduleRealInfo {
	/** 主键Id */
	@Id
	@GeneratedValue
	private Long id;
	
	/** 计划ID */
	private Long spId;

	/** 排班计划日期 */
	private Date scheduleDate;
	private String scheduleDateStr;
	
	/** 真实执行时间 yyyy-MM-dd */
	private String realExecDate;

	/** 线路名称 */
	private String xlName;
	/** 线路编码 */
	private String xlBm;

	/** 路牌名称 */
	private String lpName;

	/** 车辆自编号 */
	private String clZbh;
	
	/** 驾驶员工号 */
	private String jGh;
	/** 驾驶员名字 */
	private String jName;
	/** 售票员工号 */
	private String sGh;
	/** 售票员名字 */
	private String sName;

	/** 线路方向 */
	private String xlDir;
	/** 起点站code*/
	private String qdzCode;
	/** 起点站名字 */
	private String qdzName;
	
	/** 终点站code*/
	private String zdzCode;
	/** 终点站名字 */
	private String zdzName;

	/** 计划发车时间（格式 HH:mm） */
	private String fcsj;
	/** 计划发车时间戳*/
	@Transient
	private Long fcsjT;
	
	/** 计划终点时间（格式 HH:mm） */
	private String zdsj;
	/** 计划终点时间戳*/
	@Transient
	private Long zdsjT;
	
	/** 发车顺序号 */
	private Integer fcno;
	/** 对应班次数 */
	private Integer bcs;
	/** 计划里程 */
	private Double jhlc;

	/** 原始计划里程 （原计调的数据） */
	private Double jhlcOrig;

	/** 实际里程  这个字段被废弃*/
	private Double realMileage;
	
	/** 实际里程 */
	@Transient
	private String sjlc;
	/** 班次历时 */
	private Integer bcsj;

	/**
	 * 班次类型 TODO：正常班次、出场、进场、加油、区间班次、放空班次、放大站班次、两点间空驶
	 */
	private String bcType;

	/** 创建人 */
	@JsonIgnore
	@ManyToOne(fetch = FetchType.LAZY)
	private SysUser createBy;
	/** 修改人 */
	@JsonIgnore
	@ManyToOne(fetch = FetchType.LAZY)
	private SysUser updateBy;
	/** 创建日期 */
	@Column(updatable = false, name = "create_date", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
	private Date createDate;
	/** 修改日期 */
	@Column(name = "update_date", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
	private Date updateDate;

	/** 实际发车时间*/
	private String fcsjActual;
	/** 实际发车时间戳*/
	@Transient
	private Long fcsjActualTime;
	/**实际终点时间 */
	private String zdsjActual;
	/** 实际终点时间戳*/
	@Transient
	private Long zdsjActualTime;

	/**班次状态 0 未执行 1 正在执行 2 已执行 -1 已烂班 */
	private int status;

	private String adjustExps;
	
	/** 是否是临加班次 */
	private boolean sflj;

	/** 是否误点  （应发未发）*/
	@Transient
	private boolean late;

	/** 是否误点 （应发未到） */
	@Transient
	private boolean late2;
	/** 误点停靠时间 */
	@Transient
	private float lateMinute;

	/** 备注*/
	private String remarks;

	/** 原计划排班备注 */
	private String remark;
	
	/**待发时间（格式 HH:mm） */
	private String dfsj;
	
	/**待发时间戳 */
	@Transient
	private Long dfsjT;
	
	/** 指令下发状态  60: 已发送， 100： 设备确认收到， 200：驾驶员确认   0：失败 */
	private Integer directiveState = -1;
	
	/** “运营状态” 指令下发状态  60: 已发送， 100： 设备确认收到  0：失败*/
	private Integer opDirectiveState;
	
	/** 起点站计划到达时间 */
	@Transient
	private String qdzArrDatejh;

	/** 起点站实际到达时间 */
	@Transient
	private String qdzArrDatesj;

	/** 子任务 */
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "schedule")
	private Set<ChildTaskPlan> cTasks = new HashSet<>();

	/** 关联的公司名称 */
	private String gsName;
	/** 关联的公司编码 */
	private String gsBm;
	/** 关联的分公司名称 */
	private String fgsName;
	/** 关联的分公司编码 */
	private String fgsBm;
	/** 出场顺序号 */
	private Integer ccno;

	//待发调试（是否自动调整）
	private boolean dfAuto;
	//是否有GPS信号
	private boolean online;

	/** 是否有补发GPS信号 */
	private boolean reissue;

	public boolean isDfAuto() {
		return dfAuto;
	}

	public void setDfAuto(boolean dfAuto) {
		this.dfAuto = dfAuto;
	}

	public boolean isOnline() {
		return online;
	}

	public void setOnline(boolean online) {
		this.online = online;
	}

	public String getQdzArrDatejh() {
		return qdzArrDatejh;
	}

	public void setQdzArrDatejh(String qdzArrDatejh) {
		this.qdzArrDatejh = qdzArrDatejh;
	}

	public String getQdzArrDatesj() {
		return qdzArrDatesj;
	}

	public void setQdzArrDatesj(String qdzArrDatesj) {
		this.qdzArrDatesj = qdzArrDatesj;
	}

	public void setcTasks(Set<ChildTaskPlan> cTasks) {
		this.cTasks = cTasks;
	}

	public String getGsName() {
		return gsName;
	}

	public void setGsName(String gsName) {
		this.gsName = gsName;
	}

	public String getGsBm() {
		return gsBm;
	}

	public void setGsBm(String gsBm) {
		this.gsBm = gsBm;
	}

	public String getFgsName() {
		return fgsName;
	}

	public void setFgsName(String fgsName) {
		this.fgsName = fgsName;
	}

	public String getFgsBm() {
		return fgsBm;
	}

	public void setFgsBm(String fgsBm) {
		this.fgsBm = fgsBm;
	}

	public Integer getCcno() {
		return ccno;
	}

	public void setCcno(Integer ccno) {
		this.ccno = ccno;
	}


	/** ----------------
	@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	private RealTimeModel sjfcModel;
	@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	private RealTimeModel sjddModel;
	*/
	public void addRemarks(String remark){
		if(StringUtils.isBlank(remark))
			return;
		String old = this.getRemarks();
		if(StringUtils.isBlank(old))
			old = "";
		
		old += remark + ";";
		this.setRemarks(old);
		
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Date getScheduleDate() {
		return scheduleDate;
	}

	public void setScheduleDate(Date scheduleDate) {
		this.scheduleDate = scheduleDate;
	}

	public String getXlName() {
		return xlName;
	}

	public void setXlName(String xlName) {
		this.xlName = xlName;
	}

	public String getXlBm() {
		return xlBm;
	}

	public void setXlBm(String xlBm) {
		this.xlBm = xlBm;
	}

	public String getLpName() {
		return lpName;
	}

	public void setLpName(String lpName) {
		this.lpName = lpName;
	}

	public String getClZbh() {
		return clZbh;
	}

	public void setClZbh(String clZbh) {
		this.clZbh = clZbh;
	}

	public String getjGh() {
		return jGh;
	}

	public void setjGh(String jGh) {
		this.jGh = jGh;
	}

	public String getjName() {
		return jName;
	}

	public void setjName(String jName) {
		this.jName = jName;
	}

	public String getsGh() {
		if(sGh == null)
			return "";
		return sGh;
	}

	public void setsGh(String sGh) {
		this.sGh = sGh;
	}

	public String getsName() {
		if(sGh == null)
			return "";
		return sName;
	}

	public void setsName(String sName) {
		this.sName = sName;
	}

	public String getXlDir() {
		return xlDir;
	}

	public void setXlDir(String xlDir) {
		this.xlDir = xlDir;
	}

	public String getQdzCode() {
		return qdzCode;
	}

	public void setQdzCode(String qdzCode) {
		this.qdzCode = qdzCode;
	}

	public String getQdzName() {
		return qdzName;
	}

	public void setQdzName(String qdzName) {
		this.qdzName = qdzName;
	}

	public String getZdzCode() {
		return zdzCode;
	}

	public void setZdzCode(String zdzCode) {
		this.zdzCode = zdzCode;
	}

	public String getZdzName() {
		return zdzName;
	}

	public void setZdzName(String zdzName) {
		this.zdzName = zdzName;
	}

	public String getFcsj() {
		return fcsj;
	}

	public void setFcsj(String fcsj) {
		this.fcsj = fcsj;
	}

	public Long getFcsjT() {
		return fcsjT;
	}

	public void setFcsjT(Long fcsjT) {
		this.fcsjT = fcsjT;
	}

	public String getZdsj() {
		return zdsj;
	}

	public void setZdsj(String zdsj) {
		this.zdsj = zdsj;
	}

	public Long getZdsjT() {
		return zdsjT;
	}

	public void setZdsjT(Long zdsjT) {
		this.zdsjT = zdsjT;
	}

	public Integer getFcno() {
		return fcno;
	}

	public void setFcno(Integer fcno) {
		this.fcno = fcno;
	}

	public Integer getBcs() {
		return bcs;
	}

	public void setBcs(Integer bcs) {
		this.bcs = bcs;
	}

	public Double getJhlc() {
		return jhlc;
	}

	public void setJhlc(Double jhlc) {
		this.jhlc = jhlc;
		//临加班次 计划公里 和 实际计划公里一样
		if(this.isSflj())
			this.setJhlcOrig(this.getJhlc());
	}
	
	public String getSjlc() {
		return sjlc;
	}

	public void setSjlc(String sjlc) {
		this.sjlc = sjlc;
	}

	public Integer getBcsj() {
		return bcsj;
	}

	public void setBcsj(Integer bcsj) {
		this.bcsj = bcsj;
	}

	public String getBcType() {
		return bcType;
	}

	public void setBcType(String bcType) {
		this.bcType = bcType;
	}

	public SysUser getCreateBy() {
		return createBy;
	}

	public void setCreateBy(SysUser createBy) {
		this.createBy = createBy;
	}

	public SysUser getUpdateBy() {
		return updateBy;
	}

	public void setUpdateBy(SysUser updateBy) {
		this.updateBy = updateBy;
	}

	public Date getCreateDate() {
		return createDate;
	}

	public void setCreateDate(Date createDate) {
		this.createDate = createDate;
	}

	public Date getUpdateDate() {
		return updateDate;
	}

	public void setUpdateDate(Date updateDate) {
		this.updateDate = updateDate;
	}

	public String getFcsjActual() {
		return fcsjActual;
	}

	public void setFcsjActual(String fcsjActual) {
		this.fcsjActual = fcsjActual;
	}

	public Long getFcsjActualTime() {
		return fcsjActualTime;
	}

	public void setFcsjActualTime(Long fcsjActualTime) {
		this.fcsjActualTime = fcsjActualTime;
	}

	public String getZdsjActual() {
		return zdsjActual;
	}

	public void setZdsjActual(String zdsjActual) {
		this.zdsjActual = zdsjActual;
	}

	public Long getZdsjActualTime() {
		return zdsjActualTime;
	}

	public void setZdsjActualTime(Long zdsjActualTime) {
		this.zdsjActualTime = zdsjActualTime;
	}

	public int getStatus() {
		return status;
	}

	public void setStatus(int status) {
		this.status = status;
	}

	public String getRemarks() {
		return remarks;
	}

	public void setRemarks(String remarks) {
		this.remarks = remarks;
	}

	public String getDfsj() {
		return dfsj;
	}

	public void setDfsj(String dfsj) {
		this.dfsj = dfsj;
	}

	public Long getDfsjT() {
		return dfsjT;
	}

	public void setDfsjT(Long dfsjT) {
		this.dfsjT = dfsjT;
	}


	@Transient
	private static DateTimeFormatter fmtHHmm = DateTimeFormat.forPattern("HH:mm");
	@Transient
	private static DateTimeFormatter fmtyyyyMMddHHmm = DateTimeFormat.forPattern("yyyy-MM-ddHH:mm");

	public void setDfsjAll(Long dfsjT) {
		this.dfsjT = dfsjT;
		this.dfsj = fmtHHmm.print(this.dfsjT);
	}
	
	public void setDfsjAll(String dfsj) {
		this.dfsjT = fmtyyyyMMddHHmm.parseMillis(this.realExecDate + dfsj);
		this.dfsj = dfsj;
	}
	
	public void calcEndTime(){
		//计划终点时间
		if(this.getBcsj() != null){
			this.setZdsjT(this.getDfsjT() + (this.getBcsj() * 60 * 1000));
			this.setZdsj(fmtHHmm.print(this.zdsjT));
		}
	}

	public Integer getDirectiveState() {
		return directiveState;
	}

	public void setDirectiveState(Integer directiveState) {
		this.directiveState = directiveState;
	}

	@Override
	public boolean equals(Object obj) {
		try{
			return this.id.equals(((ScheduleRealInfo)obj).getId());
		}catch(Exception e){
			return false;
		}
	}

	@Override
	public int hashCode() {
		return ("schedule_" + this.id).hashCode();
	}

	public String getQdzArrDateJH() {
		return qdzArrDatejh;
	}

	public void setQdzArrDateJH(String qdzArrDateJH) {
		this.qdzArrDatejh = qdzArrDateJH;
	}

	public String getQdzArrDateSJ() {
		return qdzArrDatesj;
	}

	public void setQdzArrDateSJ(String qdzArrDateSJ) {
		this.qdzArrDatesj = qdzArrDateSJ;
	}

	public boolean isSflj() {
		return sflj;
	}

	public void setSflj(boolean sflj) {
		this.sflj = sflj;
	}
	
	/**
	 * 
	 * @Title: setFcsjAll 
	 * @Description: TODO(设置计划发车时间) 
	 * @throws
	 */
	public void setFcsjAll(String fcsj){
		this.fcsjT = fmtyyyyMMddHHmm.parseMillis(this.realExecDate + fcsj);
		this.fcsj = fcsj;
	}
	
	/**
	 * 
	 * @Title: setFcsjAll 
	 * @Description: TODO(设置计划发车时间) 
	 * @throws
	 */
	public void setFcsjAll(Long fcsjT){
		this.fcsjT = fcsjT;
		this.fcsj = fmtHHmm.print(fcsjT);
	}
	
	/**
	 * 
	 * @Title: setFcsjActualAll 
	 * @Description: TODO(设置实际发车时间 字符串) 
	 * @throws
	 */
	public void setFcsjActualAll(String fcsjActual){
		this.fcsjActualTime = fmtyyyyMMddHHmm.parseMillis(this.realExecDate + fcsjActual);
		this.fcsjActual = fcsjActual;
		calcStatus();
	}
	
	/**
	 * 
	 * @Title: setFcsjActualAll 
	 * @Description: TODO(设置实际发车时间 时间戳) 
	 * @throws
	 */
	public void setFcsjActualAll(Long t){
		this.fcsjActualTime = t;
		this.fcsjActual = fmtHHmm.print(t);

		//更新班次状态
		calcStatus();
	}
	
	/**
	 * 
	 * @Title: setFcsjActualAll 
	 * @Description: TODO(设置实际终点时间) 
	 * @throws
	 */
	public void setZdsjActualAll(Long t){
		this.zdsjActualTime = t;
		this.zdsjActual = fmtHHmm.print(t);
		
		//更新班次状态
		calcStatus();
	}
	
	/**
	 * 
	 * @Title: setFcsjActualAll 
	 * @Description: TODO(设置实际终点时间) 
	 * @throws
	 */
	public void setZdsjActualAll(String zdsjActual){
		this.zdsjActualTime = fmtyyyyMMddHHmm.parseMillis(this.realExecDate + zdsjActual);
		this.zdsjActual = zdsjActual;

		calcStatus();
	}
	
	public Long getSpId() {
		return spId;
	}

	public void setSpId(Long spId) {
		this.spId = spId;
	}

	public String getRealExecDate() {
		return realExecDate;
	}

	public void setRealExecDate(String realExecDate) {
		this.realExecDate = realExecDate;
	}

	public void calcStatus() {
		if(this.status == -1)
			return;
		
		this.status = 0;
		if(StringUtils.isNotBlank(this.fcsjActual)){
			this.status = 1;
			
			//进出场班次并且没有计划里程的
			if((this.bcType.equals("out") || this.bcType.equals("in"))
					&& this.jhlc == null){
				this.status = 2;
			}
		}
		if(StringUtils.isNotBlank(this.zdsjActual))
			this.status = 2;
	}
	
	public void destroy(){
		this.jhlc = 0.0;
		if(this.isSflj())
			this.jhlcOrig = 0.0;
		this.status = -1;
		this.clearFcsjActual();
	}
	
	public boolean isDestroy(){
		return this.status == -1;
	}
	
/*	public boolean isNotDestroy(){
		return this.status != -1;
	}*/

	public Set<ChildTaskPlan> getcTasks() {
		return cTasks;
	}

/*	public void setcTasks(Set<ChildTaskPlan> cTasks) {
		this.cTasks = cTasks;
	}*/

	public String getScheduleDateStr() {
		return scheduleDateStr;
	}

	public void setScheduleDateStr(String scheduleDateStr) {
		this.scheduleDateStr = scheduleDateStr;
	}
	
	public void clearFcsjActual(){
		this.setFcsjActual(null);
		this.setFcsjActualTime(null);
		this.calcStatus();
	}
	
	//清除实际终点时间
	public void clearZdsjActual(){
		this.setZdsjActual(null);
		this.setZdsjActualTime(null);
		
		calcStatus();
	}

	public Integer getOpDirectiveState() {
		return opDirectiveState;
	}

	public void setOpDirectiveState(Integer opDirectiveState) {
		this.opDirectiveState = opDirectiveState;
	}

/*	public ScheduleRealInfo getTwinsSch() {
		return twinsSch;
	}

	public void setTwinsSch(ScheduleRealInfo twinsSch) {
		this.twinsSch = twinsSch;
	}*/

	public boolean isLate() {
		return late;
	}

	public void setLate(boolean late) {
		this.late = late;
	}

	public String getAdjustExps() {
		return adjustExps;
	}

	public void setAdjustExps(String adjustExps) {
		this.adjustExps = adjustExps;
	}

	public boolean isReissue() {
		return reissue;
	}

	public void setReissue(boolean reissue) {
		this.reissue = reissue;
	}

	public Double getRealMileage() {
		return realMileage;
	}

	public void setRealMileage(Double realMileage) {
		this.realMileage = realMileage;
	}

	public Double getJhlcOrig() {
		return jhlcOrig;
	}

	public void setJhlcOrig(Double jhlcOrig) {
		this.jhlcOrig = jhlcOrig;
	}

	public void reCalcLate() {
		if(this.getStatus() == 0
				&& this.getFcsjActual() == null
			&& this.dfsjT < System.currentTimeMillis()){
			this.setLate(true);
		}
		else
			this.setLate(false);
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

	public float getLateMinute() {
		return lateMinute;
	}

	public void setLateMinute(float lateMinute) {
		this.lateMinute = lateMinute;
	}

	public boolean isLate2() {
		return late2;
	}

	public void setLate2(boolean late2) {
		this.late2 = late2;
	}
}
